import os
from xml.sax import make_parser, handler

import pygame
pygame.init()

import image_handler
from constants import *

NO_TEXTURE = "no_texture.jpg"

class MapError(Exception):
    """ Class to handle MapError exceptions """
    pass

class MapHandler(object):
    """ Class to handle Map objects """
    mapContainer = {}
    def __iter__(self):
        yield self.mapContainer.__iter__()

    def __getitem__(self, item):
        if item not in self.mapContainer:
            raise MapError("Map %s does not exist!" % item)
        return self.mapContainer[item]

    def registerMap(self, mapName):
        if mapName in self.mapContainer:
            raise MapError("Map %s has already been registed, unregister it first" % mapName)
        self.mapContainer[mapName] = Map(mapName)

class Map(object):
    """ """
    data = dict()
    def __init__(self, name):
        self.name = name
        self.parser = self.XMLParser()

    def load(self):
        print "File: %s" % os.path.join( PATH_MAPS, self.name + ".xml")
        self.data = self.parser._parse( os.path.join( PATH_MAPS, self.name + ".xml") )

    def getEntityList(self):
        return self.data['entities']

    class XMLParser(handler.ContentHandler):
        data = {}
        def _parse(self, mapFile):
            self.currentRow = 0
            self.currentTextureIndex = 0
            self.data['mapInfo']  = {}
            self.data['textures'] = []
            self.data['entities'] = {}
            
            parser = make_parser()
            parser.setContentHandler(self)
            parser.parse(mapFile)
            return self.data

        def startElement(self, name, attrs):
            """ Executed when an element in the XML is parsed """
            if name == "map":
                width  = self.data["mapInfo"]["width"] = int(attrs["width"])
                height = self.data["mapInfo"]["height"] = int(attrs["height"])

                """ Load the default textures then overwrite them later """
                while width:
                    tempHeight = height
                    self.data["textures"].append([])
                    while tempHeight:
                        self.data["textures"][-1].append(Texture())
                        tempHeight -= 1
                    width -= 1

            elif name == "texture":
                textureName = attrs["src"]
                self.data["textures"][self.currentRow][self.currentTextureIndex] = Texture(textureName)

        def endElement(self, name):
            #print "XMLParser::endElement(%s)" % (name)
            if name == "row":
                self.currentRow += 1
                self.currentTextureIndex = 0
            elif name == "texture":
                self.currentTextureIndex += 1

class Texture(pygame.sprite.Sprite):
    LOADED = False
    def __init__(self, texture = NO_TEXTURE):
        self.texture = texture
        self.texturePath = os.path.join(PATH_TEXTURES, texture)
        if not os.path.isfile(self.texturePath):
            raise MapError("Texture %s does not exist!" % texture)
        pygame.sprite.Sprite.__init__(self)

    def load(self):
        self.image  = image_handler.loadImage(self.texturePath)
        self.size   = self.image.get_size()
        self.width  = self.size[0]
        self.height = self.size[1]
        self.LOADED = True

    def blit(self, object, startPosition = (0, 0)):
        if not self.LOADED:
            self.load()
        object.blit(self.image, startPosition)

class PartTexture(Texture):
    def crop(self, cropOffset = (0, 0), startXY = (0, 0)):
        if not self.LOADED:
            self.load()
            
        self.width  -= cropOffset[0]
        self.height -= cropOffset[1]
        self.size   = (self.width, self.height)
        
        rect = pygame.Rect(startXY, (self.width, self.height))
        self.image  = pygame.transform.chop(self.image, rect)
        
        
maps = MapHandler()
maps.registerMap("test_map")
#maps["test_map"].load()